package cn.dansj.utils.message;

import cn.dansj.bean.WeComResponse;
import cn.dansj.bean.WeComSender;
import cn.dansj.bean.WeComToken;
import cn.dansj.common.request.RestTemplateUtils;
import cn.dansj.common.redis.RedisUtils;
import cn.dansj.common.utils.transfer.ArrayUtils;
import cn.dansj.common.utils.transfer.Verification;
import cn.dansj.enums.GlobalEnv;
import cn.dansj.exception.WeComConfigException;
import com.alibaba.fastjson2.JSONObject;
import org.springframework.util.DigestUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

@SuppressWarnings("all")
public class WeComUtils {

    //企业ID,必传
    private String corp;
    //应用的凭证密钥,必传
    private String secret;
    //企业应用的id,必传
    private String agent;
    //继承RestTemplate,封装user-agent属性
    //redis中存储token的key
    private String weChatTokenKey = GlobalEnv.WeComPubMsgToken;
    //消息体,各种消息传递msgBody部分,sendMsg传递收件人部分,发送完重新初始化对象
    private final JSONObject msgData = new JSONObject();

    //redis工具类
    private final RedisUtils redisUtils;
    //各种消息的请求地址
    private final String msgUrl = GlobalEnv.WeComMsgUrl;
    //文件上传地址
    private final String uploadUrl = GlobalEnv.WeComUploadUrl;
    //过期的code
    private final List<Integer> expireCode = ArrayUtils.asList(40014, 42001);
    //卡片消息的默认回调
    private final String defaultCallBackUrl = "http://localhost";

    public WeComUtils(RedisUtils redisUtils) {
        this.redisUtils = redisUtils;
    }

    /*
     * 获取各个corp+secret+agent的token,并保存在redis中
     * */
    private WeComToken getToken() {
        //从redis中获取token
        String weChatToken = redisUtils.getString(weChatTokenKey);
        WeComToken weComToken;
        //redis中没有对应的token信息
        if (Verification.checkNull(weChatToken)) {
            //获取token的请求地址
            String tokenUrl = GlobalEnv.WeComTokenUrl;
            //请求对应应用的token信息
            weComToken = RestTemplateUtils.defaultInstance().get(String.format(tokenUrl, corp, secret), WeComToken.class);
            assert weComToken != null;
            if (weComToken.getErrCode() == 0) {
                //保存进redis,避免频繁请求
                redisUtils.set(weChatTokenKey, weComToken.getAccess_token(), weComToken.getExpiresIn(), TimeUnit.SECONDS);
            }
        } else {
            weComToken = new WeComToken();
            weComToken.setErrCode(0);
            weComToken.setAccessToken(weChatToken);

        }
        return weComToken;
    }

    /*
     * 检查收件人是否有效
     * */
    private boolean checkRecipients(String user, String party, String tag) {
        return Verification.checkNull(user) && Verification.checkNull(party) && Verification.checkNull(tag);
    }

    /*
     * 检查企业信息和应用信息是否齐全
     * */
    private boolean checkCorpInfo(String agent, String corp, String secret) {
        return Verification.checkNull(agent) || Verification.checkNull(corp) || Verification.checkNull(secret);

    }

    /*
     * 设置企业信息和应用信息
     * */
    public void setCorpInfo(String corp, String secret, String agent) throws WeComConfigException {
        this.corp = corp;
        this.secret = secret;
        this.agent = agent;

        //校验企业信息和应用信息
        if (checkCorpInfo(agent, corp, secret)) {
            throw new WeComConfigException("/corp/secret/agent不完整");
        }

        String md5 = DigestUtils.md5DigestAsHex(String.format("%s:%s:%s", corp, secret, agent).getBytes());
        this.weChatTokenKey = String.format(this.weChatTokenKey, md5);
    }

    public void setCorpInfo(WeComSender weComSender) throws WeComConfigException {
        setCorpInfo(weComSender.getCorp(), weComSender.getSecret(), weComSender.getAgent());
    }

    /*
     * 发送消息的基础方法
     * */
    private WeComResponse sendMsg(JSONObject msgData, String user, String party, String tag, String msgType) {

        //校验收件人信息
        if (checkRecipients(user, party, tag)) {
            WeComResponse weComResponse = new WeComResponse();
            weComResponse.setErrCode(WeComResponse.errCodeEnum.RecipientError.getCode());
            weComResponse.setErrMsg(WeComResponse.errCodeEnum.RecipientError.getMsg());
            return weComResponse;
        }

        //添加共用消息部分
        msgData.put("toparty", party);
        msgData.put("touser", user);
        msgData.put("totag", tag);
        msgData.put("msgtype", msgType);
        msgData.put("agentid", agent);

        //获取token
        String token = getToken().getAccess_token();
        //发送消息,如果返回token过期,删除token重新获取并重新发送消息
        WeComResponse response = RestTemplateUtils.defaultInstance().post(String.format(msgUrl, token), msgData, WeComResponse.class);
        if (expireCode.contains(response.getErrCode())) {
            redisUtils.delete(weChatTokenKey);
            token = getToken().getAccess_token();
            response = RestTemplateUtils.defaultInstance().post(String.format(msgUrl, token), msgData, WeComResponse.class);
        }

        //重置对象
        msgData = new JSONObject();

        return response;
    }

    /*
     * 发送文本消息
     * */
    public WeComResponse sendTextMsg(String message, String user, String party, String tag) {
        String msgType = "text";
        JSONObject msgBody = new JSONObject();
        msgBody.put("content", message);
        msgData.put(msgType, msgBody);
        return sendMsg(msgData, user, party, tag, msgType);
    }

    /*
     * 发送文本卡片消息
     * */
    public WeComResponse sendCardMsg(String subject, String message, String user, String party, String tag, String callBackUrl) {
        String msgType = "textcard";
        JSONObject msgBody = new JSONObject();
        msgBody.put("title", subject);
        msgBody.put("description", message);
        msgBody.put("url", Verification.checkNull(callBackUrl) ? defaultCallBackUrl : callBackUrl);
        msgBody.put("btntxt", "more");
        msgData.put(msgType, msgBody);
        return sendMsg(msgData, user, party, tag, msgType);
    }

    /*
     * 发送文本卡片消息,默认回调
     * */
    public WeComResponse sendCardMsg(String subject, String message, String user, String party, String tag) {
        return sendCardMsg(subject, message, user, party, tag, defaultCallBackUrl);
    }

    /*
     * 发送任务卡片消息
     * */
    public WeComResponse sendTaskMsg(String subject,
                                     String message,
                                     String user,
                                     String party,
                                     String tag,
                                     String callBackUrl,
                                     List<JSONObject> btn) {
        String msgType = "taskcard";
        JSONObject msgBody = new JSONObject();
        msgBody.put("title", subject);
        msgBody.put("description", message);
        msgBody.put("url", callBackUrl);
        msgBody.put("task_id", String.valueOf(System.currentTimeMillis()));
        msgBody.put("btn", btn);
        msgData.put(msgType, msgBody);
        return sendMsg(msgData, user, party, tag, msgType);
    }

    /*
     * 获取默认按钮信息
     * */
    private List<JSONObject> getTaskBtn() {
        List<JSONObject> btn = new ArrayList<>();
        JSONObject btnInfo = new JSONObject();
        btnInfo.put("key", "p_key");
        btnInfo.put("name", " ");
        btnInfo.put("replace_name", " ");
        btnInfo.put("color", "red");
        btnInfo.put("is_bold", true);
        btn.add(btnInfo);
        return btn;
    }

    /*
     * 发送任务卡片消息,默认按钮
     * */
    public WeComResponse sendTaskMsg(String subject,
                                     String message,
                                     String user,
                                     String party,
                                     String tag,
                                     String callBackUrl) {
        return sendTaskMsg(subject, message, user, party, tag, callBackUrl, getTaskBtn());
    }

    /*
     * 发送任务卡片消息,默认按钮,无回调
     * */
    public WeComResponse sendTaskMsg(String subject,
                                     String message,
                                     String user,
                                     String party,
                                     String tag) {
        return sendTaskMsg(subject, message, user, party, tag, null, getTaskBtn());
    }

    /*
     * 发送任务卡片消息,无回调
     * */
    public WeComResponse sendTaskMsg(String subject,
                                     String message,
                                     String user,
                                     String party,
                                     String tag,
                                     List<JSONObject> btn) {
        return sendTaskMsg(subject, message, user, party, tag, null, btn);
    }

    /*
     * 发送文件,暂无
     * */
    public WeComResponse sendFile(String filePath, String sendType, String user, String party, String tag) {
        return new WeComResponse();
    }
}
